import java.util.LinkedList;


public class Hanoi {

	
	Hanoi(int n ){
		this.n = n;
		start = new LinkedList<Disk>(){
			private static final long serialVersionUID = -6595231752297813510L;
			public String toString(){
				return "Start-Stapel";
			}
			
		};
		goal = new LinkedList<Disk>(){
			private static final long serialVersionUID = -6552317522978123234L;
			public String toString(){
				return "Ziel-Stapel";
			}

		};
		help = new LinkedList<Disk>(){
			private static final long serialVersionUID = -6552317529781232324L;
			public String toString(){
				return "Hilfs-Stapel";
			}

		};
		move = new LinkedList<Move>();
		optMove  = new LinkedList<Move>();
		for(int i = 0; i<n; i++){
			start.add(new Disk(n-i));
		}
		solve(n, start, help,goal);
		goal.clear();
		for(int i = 0; i<n; i++){
			start.add(new Disk(n-i));
		}

	}	

	
	private boolean move(LinkedList<Disk> s, LinkedList<Disk> g) {	// Move a Disk from one Bar to another DEPRICATED
		if (s.isEmpty()){
			return false;
		}
		
		if (!g.isEmpty() && s.getLast().getSize() > g.getLast().getSize()){
			return false;
		}
		Disk d = s.removeLast();
		optMove.add(new Move(s,g,d));
		return g.add(d);
	}
	
	boolean pick(LinkedList<Disk>s){										// PickUp an Bar
		if(s.isEmpty() || picked)
			return false;
		current = new Move(s,s.removeLast());
		picked= true;
		return true;
	}
	
	public void undo() {
		if (move.size() > 0 && !picked){
			Move m = move.removeLast();
			m.from.add(m.to.removeLast());
			if (move.size() <1)
				wronMove = false;
			else
				if(move.size() <= optMove.size())
					wronMove = !move.getLast().equals(optMove.get(move.size()-1));
		}
	}
	
	boolean pull(LinkedList<Disk>g){										// Lay Back the disk							
		if(!picked)
			return false;
		if (!g.isEmpty() && current.getD().getSize() > g.getLast().getSize())
			return false;
		g.add(current.getD());
		current.setTo(g);
		move.add(current);
		picked = false;
		if(move.size() <= optMove.size())
			wronMove = !move.getLast().equals(optMove.get(move.size()-1));
		else
			wronMove = true;
		return true;
	}
	public void solve(int n, LinkedList<Disk> s,LinkedList<Disk> h, LinkedList<Disk> g,Gui u ){		// Solve the Game
	    while(wronMove){
	    	u.refresh();
	    	undo();
	    	u.getGui().update(u.getGui().getGraphics());
    		//wait(300);
    		try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	    }
    	u.refresh();
		if (!wronMove)
	    	while(!isSolved()){
		    	u.refresh();
	    		move(optMove.get(move.size()));
		    	u.getGui().update(u.getGui().getGraphics());
	    		//wait(300);
	    		try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    	}
	   }
	
	private void solve(int n, LinkedList<Disk> s,LinkedList<Disk> h, LinkedList<Disk> g){
		if (! isSolved())
			if (n > 0){
				solve (n-1, s, g, h);
				move (s,g);
				solve(n-1, h, s, g);
			}
		
	}
	private void move(Move m){
		m.getTo().add(m.getFrom().removeLast());
		move.add(m);
	}
	

	public boolean isSolved(){
		return (goal.size()  == n);
	}
	public LinkedList<Disk> getStart() {
		return start;
	}

	public LinkedList<Disk> getGoal() {
		return goal;
	}

	public LinkedList<Disk> getHelp() {
		return help;
	}

	public LinkedList<Move> getMove() {
		return move;
	}
	public boolean getPicked() {
		return picked;
	}


	public Move getCurrent() {
		return current;
	}
	public boolean getWronMove() {
		return wronMove;
	}
	
	private boolean wronMove= false;
	private Move current;
	private boolean picked= false;
	private LinkedList<Disk> start;
	private LinkedList<Disk> goal;
	private LinkedList<Disk> help;
	private LinkedList<Move> move;
	private LinkedList<Move> optMove;	

	private int n;
	/*
	public static void wait (int n){
        long t0,t1;
        t0=System.currentTimeMillis();
        do{
            t1=System.currentTimeMillis();
        }
        while (t1-t0<1000);
}*/
	
}
